---
title: Deno on AWS with SST
description: Create and deploy a Deno app to AWS with SST.
---

We are going to build an app with Deno, add an S3 Bucket for file uploads, and deploy it to AWS in a container with SST.

:::tip[View source]
You can [view the source](https://github.com/sst/sst/tree/dev/examples/aws-deno) of this example in our repo.
:::

Before you get started, make sure to [configure your AWS credentials](/docs/iam-credentials#credentials).

---

#### Examples

We also have a few other Deno examples that you can refer to.

- [Build a hit counter with Deno and Redis](/docs/examples/#aws-deno-redis)

---

## 1. Create a project

Let's start by creating our Deno app.

```bash
deno init aws-deno
```

---

#### Init Deno Serve

Replace your `main.ts` with the following.

```ts title="main.ts"
Deno.serve(async (req) => {
  const url = new URL(req.url);

  if (url.pathname === "/" && req.method === "GET") {
    return new Response("Hello World!");
  }

  return new Response("404!");
});
```

This starts up an HTTP server by default on port `8000`.

---

#### Init SST

Make sure you have [SST installed globally](/docs/reference/cli).

```bash
sst init
```

This'll create an `sst.config.ts` file in your project root.

---

## 2. Add a Service

To deploy our Deno app, let's add an [AWS Fargate](https://aws.amazon.com/fargate/) container with [Amazon ECS](https://aws.amazon.com/ecs/). Update your `sst.config.ts`.

```js title="sst.config.ts" {10-12}
async run() {
  const vpc = new sst.aws.Vpc("MyVpc");
  const cluster = new sst.aws.Cluster("MyCluster", { vpc });

  new sst.aws.Service("MyService", {
    cluster,
    loadBalancer: {
      ports: [{ listen: "80/http", forward: "8000/http" }],
    },
    dev: {
      command: "deno task dev",
    },
  });
}
```

This creates a VPC with an ECS Cluster, and adds a Fargate service to it.

:::note
By default, your service in not deployed when running in _dev_.
:::

The `dev.command` tells SST to instead run our Deno app locally in dev mode.

---

#### Start dev mode

Run the following to start dev mode. This'll start SST and your Deno app.

```bash
sst dev
```

Once complete, click on **MyService** in the sidebar and open your Deno app in your browser.

---

## 3. Add an S3 Bucket

Let's add an S3 Bucket for file uploads. Add this to your `sst.config.ts` below the `Vpc` component.

```ts title="sst.config.ts"
const bucket = new sst.aws.Bucket("MyBucket");
```

---

#### Link the bucket

Now, link the bucket to the container.

```ts title="sst.config.ts" {3}
new sst.aws.Service("MyService", {
  // ...
  link: [bucket],
});
```

This will allow us to reference the bucket in our Deno app.

---

## 4. Upload a file

We want a `POST` request made to the `/` route to upload a file to our S3 bucket. Let's add this below our _Hello World_ route in our `main.ts`.

```ts title="main.ts" {6}
if (url.pathname === "/" && req.method === "POST") {
  const formData: FormData = await req.formData();
  const file: File | null = formData?.get("file") as File;

  const params = {
    Bucket: Resource.MyBucket.name,
    ContentType: file.type,
    Key: file.name,
    Body: file,
  };
  const upload = new Upload({
    params,
    client: s3,
  });
  await upload.done();

  return new Response("File uploaded successfully.");
}
```

:::tip
We are directly accessing our S3 bucket with `Resource.MyBucket.name`.
:::

Add the imports. We'll use the extra ones below.

```ts title="main.ts"
import { Resource } from "sst";
import {
  S3Client,
  GetObjectCommand,
  ListObjectsV2Command,
} from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client();
```

And install the npm packages.

```bash
deno install npm:sst npm:@aws-sdk/client-s3 npm:@aws-sdk/lib-storage npm:@aws-sdk/s3-request-presigner
```

---

## 5. Download the file

We'll add a `/latest` route that'll download the latest file in our S3 bucket. Let's add this below our upload route in `main.ts`.

```ts title="main.ts"
if (url.pathname === "/latest" && req.method === "GET") {
  const objects = await s3.send(
    new ListObjectsV2Command({
      Bucket: Resource.MyBucket.name,
    }),
  );
  const latestFile = objects.Contents!.sort(
    (a, b) =>
      (b.LastModified?.getTime() ?? 0) - (a.LastModified?.getTime() ?? 0),
  )[0];
  const command = new GetObjectCommand({
    Key: latestFile.Key,
    Bucket: Resource.MyBucket.name,
  });
  return Response.redirect(await getSignedUrl(s3, command));
}
```

---

#### Test your app

To upload a file run the following from your project root. You might have to go to the `MyService` tab in the sidebar and accept the Deno permission prompts.

```bash
curl -F file=@deno.json http://localhost:8000/
```

This should upload the `deno.json`. Now head over to `http://localhost:8000/latest` in your browser and it'll show you what you just uploaded.

---

## 5. Deploy your app

To deploy our app we'll first add a `Dockerfile`.

```dockerfile title="Dockerfile"
FROM denoland/deno

EXPOSE 8000

USER deno

WORKDIR /app

ADD . /app

RUN deno install --entrypoint main.ts

CMD ["run", "--allow-all",  "main.ts"]
```

:::tip
You need to be running [Docker Desktop](https://www.docker.com/products/docker-desktop/) to deploy your app.
:::

Now to build our Docker image and deploy we run:

```bash
sst deploy --stage production
```

You can use any stage name here but it's good to create a new stage for production. This'll give the URL of your Deno app deployed as a Fargate service.

```bash
✓  Complete
   MyService: http://prod-MyServiceLoadBalanc-491430065.us-east-1.elb.amazonaws.com
```

---

## Connect the console

As a next step, you can setup the [SST Console](/docs/console/) to _**git push to deploy**_ your app and view logs from it.

![SST Console Autodeploy](../../../../../assets/docs/start/sst-console-autodeploy.png)

You can [create a free account](https://console.sst.dev) and connect it to your AWS account.
